home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
alpha
/
dipc
/
dipc-0.000
/
dipc-0
/
dipc-0.15
/
dipcd
/
support.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-16
|
10KB
|
459 lines
/*
* support.c
*
* part of dipcd source code
*
* Copyright (C) Kamran Karimi
*/
#include "dipcd.h"
#include "funcs.h"
extern struct sockaddr_in MY_LBACK, REFEREE_LBACK;
extern struct sockaddr_in MY_ADDRESS, REFEREE_ADDRESS;
extern int verbose;
char mstr[160];
/* prints a message for the user */
void mess(char *str, char *filename, int line)
{
fprintf(stderr,"[%d@%s:%d] %s\n",getpid(), filename, line, str);
}
/** The following is for the support of heterogeneous systems **/
/* converts a 16 bit integer from big/little endian to little/big endian */
/*static*/ short endian16(short to_convert)
{
char temp;
union
{
short short_form;
char chr_form[2];
} conv;
conv.short_form = to_convert;
temp = conv.chr_form[0];
conv.chr_form[0] = conv.chr_form[1];
conv.chr_form[1] = temp;
return conv.short_form;
}
/* converts a 32 bit integer from big/little endian to little/big endian */
/*static*/ int endian32(int to_convert)
{
char temp;
union
{
int int_form;
char chr_form[4];
} conv;
conv.int_form = to_convert;
temp = conv.chr_form[0];
conv.chr_form[0] = conv.chr_form[3];
conv.chr_form[3] = temp;
temp = conv.chr_form[1];
conv.chr_form[1] = conv.chr_form[2];
conv.chr_form[2] = temp;
return conv.int_form;
}
/* put here the code to convert the fields of a message structure to
the receiving machine's suitable form. message.arch has the architecture
of the sender machine. MY_DIPC_ARCH has the architecture of this machine.*/
static void convert_message(struct message *message)
{
if(message->arch == MY_DIPC_ARCH)
return;
/* else convert (struct message*) message */
}
/* this routine is the place where data conversions for different computer
architectures are done. This is done after we have converted the message
itself. see above. */
static void convert_data(char *data, struct message *message)
{
if(message->arch == MY_DIPC_ARCH)
return;
switch(message->info.func)
{
case SEMCTL:
/* 'message->info.arg2' has the second (semnum) argument */
switch(message->info.arg3)
{
case SETVAL:
/* convert (int) message->info.arg4 */
break;
case IPC_SET:
case IPC_STAT:
/* convert (struct semid_ds *) data */
break;
case SETALL:
case GETALL:
/* convert (ushort *)data */
break;
}
break;
case SEMOP:
/* 'message->info.arg2' has the third (nops) argument */
/* convert (struct sembuf *) data */
break;
case MSGCTL:
/* convert (struct msqid_ds *) data */
break;
case SHMCTL:
/* (struct shmid_ds *) data */
break;
default:
sprintf(mstr,"ERROR: Unknown Function");
mess(mstr, INFO);
break;
}
}
/** End of heterogeneous support routines **/
char *work_string(int func)
{
static char strings[23][11] =
{
"SEMOP ",
"SEMCTL ",
"MSGSND ",
"MSGRCV ",
"MSGCTL ",
"SHMCTL ",
"DISABLE_RD",
"DISABLE_WR",
"WANTRD ",
"WANTWR ",
"DETACH ",
"AK ",
"WRPROT_SND",
"RDPROT ",
"RDPROT_SND",
"NOP_SND ",
"RCV ",
"TSTGET ",
"RMID ",
"DELKEY ",
"SEARCH ",
"COMMIT ",
"Bad Work "
};
switch(func)
{
case SEMOP: return strings[0];
case SEMCTL: return strings[1];
case MSGSND: return strings[2];
case MSGRCV: return strings[3];
case MSGCTL: return strings[4];
case SHMCTL: return strings[5];
case DISABLE_RD: return strings[6];
case DISABLE_WR: return strings[7];
case WANTRD: return strings[8];
case WANTWR: return strings[9];
case DETACH: return strings[10];
case AK: return strings[11];
case WRPROT_SND: return strings[12];
case RDPROT: return strings[13];
case RDPROT_SND: return strings[14];
case NOP_SND: return strings[15];
case RCV: return strings[16];
case TSTGET: return strings[17];
case RMID: return strings[18];
case DELKEY: return strings[19];
case SEARCH: return strings[20];
case COMMIT: return strings[21];
default:
break;
}
sprintf(mstr,"ERROR: Bad Work function: %d", func);
mess(mstr, INFO);
return strings[22];
}
char *request_string(int req)
{
static char strings[7][12] =
{
"REQ_SHMMAN ",
"RES_SHMMAN ",
"REQ_REFEREE",
"RES_REFEREE",
"REQ_DOWORK ",
"RES_DOWORK ",
"Bad Request"
};
switch(req)
{
case REQ_SHMMAN: return strings[0];
case RES_SHMMAN: return strings[1];
case REQ_REFEREE: return strings[2];
case RES_REFEREE: return strings[3];
case REQ_DOWORK: return strings[4];
case RES_DOWORK: return strings[5];
default:
break;
}
sprintf(mstr,"ERROR: Bad Request: %d", req);
mess(mstr, INFO);
return strings[6];
}
/* read nbytes from the network and put them in *ptr */
int readn(int fd, char *ptr, int nbytes)
{
int nleft, nread;
nleft = nbytes;
while(nleft > 0)
{
nread = read(fd,ptr,nleft);
if(nread < 0)
{
if(errno != EINTR)
break;
}
if(nread == 0) break;
if(nread > 0)
{
nleft -= nread;
ptr += nread;
}
}
return (nbytes - nleft);
}
/* send nbytes from *ptr to the network */
int writen(int fd, char *ptr, int nbytes)
{
int nleft,nwritten;
nleft = nbytes;
while(nleft > 0)
{
nwritten = write(fd,ptr,nleft);
if(nwritten < 0)
{
if(errno != EINTR)
break;
}
if(nwritten == 0) break;
if(nwritten > 0)
{
nleft -= nwritten;
ptr += nwritten;
}
}
return (nbytes - nleft);
}
/* prepare a socket to receive incoming conections */
FD plug(int family, struct sockaddr *my_addr, int addr_len)
{
FD sockfd;
if((sockfd = socket(family,SOCK_STREAM,0)) < 0)
{
sprintf(mstr,"ERROR: socket() Failed BECAUSE %s",strerror(errno));
mess(mstr, INFO);
return BAD_FD;
}
if(bind(sockfd,my_addr,addr_len) < 0)
{
sprintf(mstr,"ERROR: bind() Failed BECAUSE %s",strerror(errno));
mess(mstr, INFO);
close(sockfd);
return BAD_FD;
}
if(listen(sockfd,5) < -1)
{
sprintf(mstr,"ERROR: listen() Failed BECAUSE %s",strerror(errno));
mess(mstr, INFO);
close(sockfd);
return BAD_FD;
}
return sockfd;
}
/* get a socket connection to another waiting one */
FD ring(int family, struct sockaddr *addr, int addr_len)
{
int sockfd;
sigset_t newmask, oldmask;
sigemptyset(&newmask);
sigaddset(&newmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &newmask, &oldmask);
while(1)
{
if((sockfd = socket(family,SOCK_STREAM,0)) < 0)
{
if(errno != EINTR)
{
sprintf(mstr,"ERROR: socket() Failed BECAUSE %s",strerror(errno));
mess(mstr, INFO);
sigprocmask(SIG_SETMASK, &oldmask, NULL);
return BAD_FD;
}
}
else break;
}
if(family == AF_INET)
{
if(SAME_ADDRESS((struct sockaddr_in *)addr, MY_ADDRESS))
(struct sockaddr_in *)addr = &MY_LBACK;
else if(SAME_ADDRESS((struct sockaddr_in *)addr, REFEREE_ADDRESS) &&
SAME_MACHINE((struct sockaddr_in *)addr,MY_ADDRESS))
(struct sockaddr_in *)addr = &REFEREE_LBACK;
}
/* connect() may not be able to restart in case of an intr */
while(1)
{
if(connect(sockfd, addr, addr_len) < 0)
{
if(errno != EINTR)
{
sprintf(mstr,"ERROR: connect() Failed BECAUSE %s",strerror(errno));
mess(mstr, INFO);
close(sockfd);
sigprocmask(SIG_SETMASK, &oldmask, NULL);
return BAD_FD;
}
}
else break;
}
sigprocmask(SIG_SETMASK, &oldmask, NULL);
return sockfd;
}
/* send the contents of a struct message over an internet connection */
BOOLEAN send_in_message(struct message *message, struct sockaddr_in addr)
{
int in_sock;
int want_trans, act_trans;
message->arch = MY_DIPC_ARCH;
message->reserved = -1;
in_sock = ring(AF_INET, (struct sockaddr *) &addr, sizeof(addr));
if(in_sock < 0)
{
sprintf(mstr,"ERROR: Can't Connect To Internet address BECAUSE %s",
strerror(errno));
mess(mstr, INFO);
return FAIL;
}
want_trans = sizeof(*message);
act_trans = writen(in_sock, (char *)message, want_trans);
if(act_trans < want_trans)
{
sprintf(mstr,"ERROR: Sent %d From %d Bytes BECAUSE %s",
act_trans, want_trans,strerror(errno));
mess(mstr, INFO);
close(in_sock);
return FAIL;
}
close(in_sock);
return SUCCESS;
}
/* receive some data (for example message contents) over an internet
connection */
int get_in_data(int in_sock, char *data, struct message *message)
{
int act_trans;
act_trans = readn(in_sock, data, message->info.dsize);
if(act_trans == message->info.dsize)
convert_data(data, message);
return act_trans;
}
/* receive an struct message from an internet connection */
int get_in_message(int in_sock, struct message *message)
{
int act_trans;
act_trans = readn(in_sock, (char *)message, sizeof(struct message));
if(act_trans == sizeof(struct message))
convert_message(message);
return act_trans;
}
/* called from front_end.c and back_end.c, when a child exits */
void child_handler(int signo)
{
pid_t cpid;
/* consider the possibility of multiple exits */
while((cpid = waitpid(-1, NULL, WNOHANG)) > 0)
{
if(verbose)
{
sprintf(mstr,"Child %d Exited",cpid);
mess(mstr, INFO);
}
}
}
BOOLEAN become(char *user)
{
struct passwd *pw;
pw = getpwnam(user);
if(pw)
{
if((setegid(pw->pw_gid) < 0) || (seteuid(pw->pw_uid) < 0))
{
sprintf(mstr,"ERROR: Can't Become: %s, uid: %d, gid: %d. Because: %s",
user, pw->pw_uid, pw->pw_gid, strerror(errno));
mess(mstr, INFO);
printf("euid %d egid %d uid %d gid %d\n",geteuid(), getegid(),
getuid(), getgid());
return FAIL;
}
return SUCCESS;
}
sprintf(mstr,"ERROR: User '%s' Not Found", user);
mess(mstr, INFO);
return FAIL;
}